﻿/*
 *  ============================================================================
 *  Name:           Gestão de parques de estacionamento
 *  Author:         João Faria
 *  Email:          a8836@alunos.ipca.pt
 *                  jfaria.gmr@gmail.com
 *  Version:        0
 *  Date:           2013-04-10
 *  Copyright:       
 *  Description:    IPCA - Programação II
 *                  Projecto final
 *  ============================================================================
 */

using System;
using System.Collections.Generic;
using GesParking.BusinessObjects;
using GesParking.DataLayer;
using GesParking.Exceptions;

namespace GesParking.BusinessLayer
{
    /// <summary>
    /// Classe que gere as entradas e saidas dos estacionamentos
    /// </summary>
    public class ParkingRegistryBL
    {
        #region Estado

        ParkingRegistrysDL registrys;
        HistoryParkingsDL history;

        #endregion

        #region Propriedades

        /// <summary>
        /// Propriedade registrys
        /// </summary>
        public ParkingRegistrysDL Registrys
        {
            get { return registrys; }
            set { registrys = value; }
        }

        #endregion

        #region construtor

        /// <summary>
        /// Construtor por omissão
        /// </summary>
        public ParkingRegistryBL()
        {
            history = new HistoryParkingsDL();
            registrys=new ParkingRegistrysDL();
        }

        #endregion

        #region Metodos da classe

        /// <summary>
        /// Conta o numero de estacionamentos num parque
        /// </summary>
        /// <param name="p">Parque</param>
        /// <returns>Numero de estacionamentos</returns>
        public static int Count(Guid p)
        {
            int count = 0;
            IEnumerator<ParkingRegistryBO> enu = ParkingRegistrysDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.ParkId == p)
                {
                    count++;
                }
            }
            return count;
        }

        #endregion

        #region Metodos pakings

        /// <summary>
        /// Verifica se user esta parqueado
        /// </summary>
        /// <param name="u">User</param>
        /// <returns>True caso já esteja parqueado</returns>
        private bool CheckUserParked(UserBO u)
        {
            IEnumerator<ParkingRegistryBO> enu = ParkingRegistrysDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.UserId == u.Id)
                {
                    return true;
                }
            }
            return false;
        }
        
        /// <summary>
        /// Verifica se user esta parqueado
        /// </summary>
        /// <param name="u">User</param>
        /// <returns>True caso já esteja parqueado</returns>
        private bool CheckUserParked(Guid u)
        {
            IEnumerator<ParkingRegistryBO> enu = ParkingRegistrysDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.UserId == u)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Verifica se user esta parqueado num determinado parque
        /// </summary>
        /// <param name="u">User</param>
        /// <param name="p">Park</param>
        /// <returns>True caso já esteja parqueado</returns>
        private bool CheckUserParked(UserBO u, ParkBo p, out ParkingRegistryBO pr)
        {
            IEnumerator<ParkingRegistryBO> enu = ParkingRegistrysDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.UserId == u.Id && enu.Current.ParkId == p.Id)
                {
                    pr = enu.Current;
                    return true;
                }
            }
            pr = new ParkingRegistryBO();
            return false;
        }

        /// <summary>
        /// Verifica se user esta parqueado num determinado parque
        /// </summary>
        /// <param name="u">User</param>
        /// <param name="p">Park</param>
        /// <returns>True caso já esteja parqueado</returns>
        private bool CheckUserParked(Guid u, Guid p, out ParkingRegistryBO pr)
        {
            IEnumerator<ParkingRegistryBO> enu = ParkingRegistrysDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.UserId == u && enu.Current.ParkId == p)
                {
                    pr = enu.Current;
                    return true;
                }
            }
            pr = new ParkingRegistryBO();
            return false;
        }

        /// <summary>
        /// Verifica se um parque está cheio
        /// </summary>
        /// <param name="p">Parque</param>
        /// <returns>True caso esteja cheio</returns>
        private bool CheckParkCapacity(ParkBo p)
        {
            int count = 0;
            IEnumerator<ParkingRegistryBO> enu = ParkingRegistrysDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.ParkId == p.Id)
                {
                    count++;
                }
            }
            return (count == p.MaxLoad);
        }

        /// <summary>
        /// Verifica se um parque está cheio
        /// </summary>
        /// <param name="p">Parque</param>
        /// <returns>True caso esteja cheio</returns>
        private bool CheckParkCapacity(Guid p)
        {
            int count = 0;
            IEnumerator<ParkingRegistryBO> enu = ParkingRegistrysDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.ParkId == p)
                {
                    count++;
                }
            }
            return (count == ParksBL.Get(p).MaxLoad);
        }

        /// <summary>
        /// Registo de entrada no estacionamento
        /// </summary>
        /// <param name="userId">User</param>
        /// <param name="parkId">Park</param>
        /// <returns>True caso o estacionamento seja efectuado</returns>
        public bool ParkIn(Guid userId, Guid parkId)
        {
            if (!ParksBL.ExisteParqueBL(parkId)) throw new ParkNotFoundException();
            if (!UsersBL.ExisteUserBL(userId)) throw new UserNotFoundException();
            if (CheckUserParked(userId)) throw new UserAlreadyParkedException();
            if (CheckParkCapacity(parkId)) throw new ParkFullException();
            ParkingRegistrysDL.AddDL(new ParkingRegistryBO(Guid.NewGuid(), DateTime.Now, userId, parkId));
            ParkingRegistrysDL.Alterado = true;
            return true;
        }

        /// <summary>
        /// Registo de entrada no estacionamento
        /// </summary>
        /// <param name="p">Parque</param>
        /// <param name="u">Utilizador</param>
        /// <returns>True caso o estacionamento seja efectuado</returns>
        public bool ParkIn(ParkBo p, UserBO u)
        {
            if (!ParksBL.ExisteParqueBL(p)) throw new ParkNotFoundException();
            if (!UsersBL.ExisteUserBL(u)) throw new UserNotFoundException();
            if (CheckUserParked(u)) throw new UserAlreadyParkedException();
            if (CheckParkCapacity(p)) throw new ParkFullException();
            ParkingRegistrysDL.AddDL(new ParkingRegistryBO(Guid.NewGuid(), DateTime.Now, u.Id, p.Id));
            ParkingRegistrysDL.Alterado = true;
            return true;
        }

        /// <summary>
        /// Desparquear utilizador
        /// </summary>
        /// <param name="p">park</param>
        /// <param name="u">Utilizador</param>
        /// <returns>True caso seja retirado do parqueamento</returns>
        public bool ParkOut(ParkBo p, UserBO u)
        {
            ParkingRegistryBO pr=new ParkingRegistryBO();
            if(!CheckUserParked(u, p, out pr)) throw new UserNotFoundInParkException();
            if (!pr.Payed) throw new ParkNotPayedException();
            pr.DtOut = DateTime.Now;
            HistoryParkingsDL.AddDL(pr);
            ParkingRegistrysDL.RemoveDL(pr);
            ParkingRegistrysDL.Alterado=true;
            return true;
        }

        /// <summary>
        /// Desparquear utilizador
        /// </summary>
        /// <param name="p">park</param>
        /// <param name="u">Utilizador</param>
        /// <returns>True caso seja retirado do parqueamento</returns>
        public bool ParkOut(Guid u, Guid p)
        {
            ParkingRegistryBO pr = new ParkingRegistryBO();
            if (!CheckUserParked(u, p, out pr)) throw new UserNotFoundInParkException();
            if (!pr.Payed) throw new ParkNotPayedException();
            pr.DtOut = DateTime.Now;
            HistoryParkingsDL.AddDL(pr);
            ParkingRegistrysDL.RemoveDL(pr);
            ParkingRegistrysDL.Alterado = true;
            return true;
        }

        /// <summary>
        /// Lista todos os registo de estacionamento
        /// </summary>
        /// <returns>Lista de registos</returns>
        public List<ParkingRegistryBO> ListParkingsBL()
        {
            List<ParkingRegistryBO> lpr = new List<ParkingRegistryBO>();
            lpr = ParkingRegistrysDL.ListDL();
            return lpr;
        }

        /// <summary>
        /// Lista todos os registos de um parque
        /// </summary>
        /// <param name="p">Parque</param>
        /// <returns>Lista de registos</returns>
        public List<ParkingRegistryBO> ListParkingsBL(ParkBo p)
        {
            List<ParkingRegistryBO> lpr = new List<ParkingRegistryBO>();
            IEnumerator<ParkingRegistryBO> enu = ParkingRegistrysDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.ParkId == p.Id)
                {
                    lpr.Add(enu.Current);
                }
            }
            return lpr;
        }

        /// <summary>
        /// Lista registos entre datas
        /// </summary>
        /// <param name="min">Data minima</param>
        /// <param name="max">Data máxima</param>
        /// <returns>Lista de registos</returns>
        public List<ParkingRegistryBO> ListParkingsBL(DateTime min, DateTime max)
        {
            List<ParkingRegistryBO> lpr = new List<ParkingRegistryBO>();
            IEnumerator<ParkingRegistryBO> enu = ParkingRegistrysDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.DtIn>=min && enu.Current.DtIn<=max)
                {
                    lpr.Add(enu.Current);
                }
            }
            return lpr;
        }

        /// <summary>
        /// Lista registos entre datas de determinado parque
        /// </summary>
        /// <param name="min">Data minima</param>
        /// <param name="max">Data máxima</param>
        /// <param name="p">Parque</param>
        /// <returns>Lista de registos</returns>
        public List<ParkingRegistryBO> ListParkingsBL(DateTime min, DateTime max, ParkBo p)
        {
            List<ParkingRegistryBO> lpr = new List<ParkingRegistryBO>();
            IEnumerator<ParkingRegistryBO> enu = ParkingRegistrysDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.DtIn >= min && enu.Current.DtIn <= max && enu.Current.Id==p.Id)
                {
                    lpr.Add(enu.Current);
                }
            }
            return lpr;
        }

        /// <summary>
        /// Grava os dados dos estacionamentos
        /// </summary>
        public void SaveParkings()
        {
            /* 
             * Falta tratar erros com acessos e permissões de ficheiros
             */
            ParkingRegistrysDL.SaveParkings();
        }

        /// <summary>
        /// Classe que lê os dados dos estacionamentos
        /// </summary>
        public void ReadParkings()
        {
            /* 
             * Falta tratar erros com acessos e permissões de ficheiros
             */
            ParkingRegistrysDL.ReadParkings();
        }

        #endregion

        #region Metodos historico

        /// <summary>
        /// Lista todos os registo de estacionamento
        /// </summary>
        /// <returns>Lista de registos</returns>
        public List<ParkingRegistryBO> ListHistoryBL()
        {
            List<ParkingRegistryBO> lpr = new List<ParkingRegistryBO>();
            lpr = HistoryParkingsDL.ListDL();
            return lpr;
        }

        /// <summary>
        /// Lista todos os registos de um parque
        /// </summary>
        /// <param name="p">Parque</param>
        /// <returns>Lista de registos</returns>
        public List<ParkingRegistryBO> ListHistoryBL(ParkBo p)
        {
            List<ParkingRegistryBO> lpr = new List<ParkingRegistryBO>();
            IEnumerator<ParkingRegistryBO> enu = HistoryParkingsDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.ParkId == p.Id)
                {
                    lpr.Add(enu.Current);
                }
            }
            return lpr;
        }

        /// <summary>
        /// Lista todos os registos de um user
        /// </summary>
        /// <param name="p">User</param>
        /// <returns>Lista de registos</returns>
        public List<ParkingRegistryBO> ListHistoryBL(UserBO u)
        {
            List<ParkingRegistryBO> lpr = new List<ParkingRegistryBO>();
            IEnumerator<ParkingRegistryBO> enu = HistoryParkingsDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.UserId == u.Id)
                {
                    lpr.Add(enu.Current);
                }
            }
            return lpr;
        }

        /// <summary>
        /// Lista registos entre datas
        /// </summary>
        /// <param name="min">Data minima</param>
        /// <param name="max">Data máxima</param>
        /// <returns>Lista de registos</returns>
        public List<ParkingRegistryBO> ListHistoryBL(DateTime min, DateTime max)
        {
            List<ParkingRegistryBO> lpr = new List<ParkingRegistryBO>();
            IEnumerator<ParkingRegistryBO> enu = HistoryParkingsDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.DtIn >= min && enu.Current.DtIn <= max)
                {
                    lpr.Add(enu.Current);
                }
            }
            return lpr;
        }

        /// <summary>
        /// Lista registos entre datas de determinado parque
        /// </summary>
        /// <param name="min">Data minima</param>
        /// <param name="max">Data máxima</param>
        /// <param name="p">Parque</param>
        /// <returns>Lista de registos</returns>
        public List<ParkingRegistryBO> ListHistoryBL(DateTime min, DateTime max, ParkBo p)
        {
            List<ParkingRegistryBO> lpr = new List<ParkingRegistryBO>();
            IEnumerator<ParkingRegistryBO> enu = HistoryParkingsDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.DtIn >= min && enu.Current.DtIn <= max && enu.Current.ParkId == p.Id)
                {
                    lpr.Add(enu.Current);
                }
            }
            return lpr;
        }

        /// <summary>
        /// Lista registos entre datas de determinado parque
        /// </summary>
        /// <param name="min">Data minima</param>
        /// <param name="max">Data máxima</param>
        /// <param name="p">Parque</param>
        /// <returns>Lista de registos</returns>
        public List<ParkingRegistryBO> ListHistoryBL(DateTime min, DateTime max, UserBO p)
        {
            List<ParkingRegistryBO> lpr = new List<ParkingRegistryBO>();
            IEnumerator<ParkingRegistryBO> enu = HistoryParkingsDL.ListDL().GetEnumerator();
            while (enu.MoveNext())
            {
                if (enu.Current.DtIn >= min && enu.Current.DtIn <= max && enu.Current.UserId == p.Id)
                {
                    lpr.Add(enu.Current);
                }
            }
            return lpr;
        }

        /// <summary>
        /// Grava os dados do historico de estacionamentos
        /// </summary>
        public void SaveHistory()
        {
            /* 
             * Falta tratar erros com acessos e permissões de ficheiros
             */
            HistoryParkingsDL.SaveHistory();
        }

        /// <summary>
        /// Classe que lê os dados do historico de estacionamentos
        /// </summary>
        public void ReadHistory()
        {
            /* 
             * Falta tratar erros com acessos e permissões de ficheiros
             */
            HistoryParkingsDL.ReadHistory();
        }

        #endregion
    }
}
